from typing import Set
from Cut import Cut
from GetStopWords import GetStopWrods
import os

def computeDistance(tmpIndexList, indexList):
    distance = 1
    for i in range(len(indexList)):
        distance = distance + tmpIndexList[i] * indexList[i]
    return 1.0 / distance

def takeFirst(item):
    return item[0]

class KNN():

    def __init__(self):
        self.defaults = {}
        self.classPaths = []
        self.wordsContainer = []
        self.wordsDictionary = {}
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        for dir in CLASSES_LIST:
            self.defaults[dir + "WordMatrix"] = []
            self.defaults[dir + "IndexMatrix"] = []
            self.defaults[dir + "WordContainer"] = []
            self.defaults[dir + "WordDictionary"] = {}
        self.__dict__.update(self.defaults)

    def setWordsContainer(self):
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        for dir in CLASSES_LIST:
            #print(CLASSES_PATH + dir + "/")
            classPath = CLASSES_PATH + dir + "/"
            self.classPaths.append(classPath)
            files = os.listdir(classPath)
            for file in files:
                filepath = classPath + file
                stopWordsPath = "stopwords.txt"
                g = GetStopWrods()
                stopWords = g.Call(stopWordsPath)
                c = Cut(stopWords)
                wordsList = c.Call(filepath)
                self.__dict__[dir + "WordMatrix"].append(wordsList)
                self.__dict__[dir + "WordContainer"].extend(wordsList)
                self.__dict__[dir + "WordContainer"] = list(set(self.__dict__[dir + "WordContainer"]))
                self.wordsContainer.extend(wordsList)
                self.wordsContainer = list(set(self.wordsContainer))
                print(str(len(self.wordsContainer)) + "\n")

    def setWordsDictionary(self):
        print("WordsDictionary Set begin." + "\n")
        for i in range(len(self.wordsContainer)):
            self.wordsDictionary[self.wordsContainer[i]] = i
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        for dir in CLASSES_LIST:
            for i in range(len(self.__dict__[dir + "WordContainer"])):
                self.__dict__[dir + "WordDictionary"][self.__dict__[dir + "WordContainer"][i]] = i
        print("WordsDictionary Set end." + "\n")
    
    def setIndexMatrix(self):
        print("IndexMatrix Set begin." + "\n")
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        for dir in CLASSES_LIST:
            print("dir \n")
            for list in self.__dict__[dir + "WordMatrix"]:
                tmpList = []
                for i in range(len(list)):
                    tmpList.append(self.wordsDictionary[list[i]])
                self.__dict__[dir + "IndexMatrix"].append(tmpList)
        print("IndexMatrix Set end." + "\n")

    # def setConditionalProbability(self):
    #     print("ConditionalProbability Set begin." + "\n")
    #     CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
    #     CLASSES_LIST = os.listdir(CLASSES_PATH)
    #     for dir in CLASSES_LIST:
    #         print("dir \n")
    #         SUM = len(self.__dict__[dir + "WordContainer"])
    #         self.__dict__[dir + "CP"] = [1.0 for i in range(len(self.__dict__[dir + "WordContainer"]))]
    #         for list in range(len(self.__dict__[dir + "BoolMatrix"])):
    #             for i in range(len(self.__dict__[dir + "WordContainer"])):
    #                 self.__dict__[dir + "CP"][i] = self.__dict__[dir + "CP"][i] + self.__dict__[dir + "BoolMatrix"][list][i]
    #                 SUM = SUM + self.__dict__[dir + "BoolMatrix"][list][i]
    #         self.__dict__[dir + "SUM"] = SUM
    #         for i in range(len(self.__dict__[dir + "WordContainer"])):
    #             self.__dict__[dir + "CP"][i] = self.__dict__[dir + "CP"][i] / SUM
    #     print("ConditionalProbability Set end." + "\n")
    
    def train(self):
        self.setWordsContainer()
        self.setWordsDictionary()
        self.setIndexMatrix()
        # self.setConditionalProbability()

    def predict(self, filepath, kNumber):
        print("Predict begin." + "\n")
        stopWordsPath = "stopwords.txt"
        g = GetStopWrods()
        stopWords = g.Call(stopWordsPath)
        c = Cut(stopWords)
        wordsList = c.Call(filepath)
        CLASSES_PATH = os.path.dirname(os.path.abspath(__file__)) + "/" + "20_newsgroups" + "/"
        CLASSES_LIST = os.listdir(CLASSES_PATH)
        distanceContainer = []
        indexList = [0 for i in range(len(self.wordsDictionary))]
        # tmpProbability = 1.0
        for i in range(len(wordsList)):
            indexList[self.wordsDictionary[wordsList[i]]] = 1
        tmpIndexList = [0 for i in range(len(self.wordsDictionary))]
        for dir in CLASSES_LIST:
            for selflist in self.__dict__[dir + "IndexMatrix"]:
                for i in range(len(selflist)):
                    tmpIndexList[selflist[i]] = 1
                distance = computeDistance(tmpIndexList, indexList)
                distanceAndDir = [distance, dir]
                distanceContainer.append(distanceAndDir)
                for i in range(len(tmpIndexList)):
                    tmpIndexList[i] = 0
        distanceContainer.sort(key = takeFirst)
        print("Predict end." + "\n")
        votingDictionary = {}
        for dir in CLASSES_LIST:
            votingDictionary[dir] = 0
        for i in range(kNumber):
            votingDictionary[distanceContainer[i][1]] += 1
        maxClass = ""
        maxNumber = 0.0
        for dir, votingNumber in votingDictionary.items():
            if votingNumber > maxNumber:
                maxClass = dir
                maxNumber = votingNumber
        return maxClass, maxNumber / kNumber

s = KNN()
s.train()
predClass, predProbability = s.predict("52558", 100)
print(predClass)